#ifndef __GLF_STR_H_INCLUDED__
#define __GLF_STR_H_INCLUDED__

#include <glf/config.h>

#include <string>

namespace glf {

	int Wcsicmp(const wchar_t* str1, const wchar_t* str2);

	int Sprintf(char *str, const char* format, ...);
	int Vsprintf(char *str, const char* format, glfVaList args);

	int Snprintf(char *str, size_t N, const char *format, ...);
	int Vsnprintf(char *str, size_t N, const char *format, glfVaList args);

	int Vsprintf_s(char* str, size_t N, const char* format, glfVaList args);
	int Vsnprintf_s(char* str, size_t N, size_t maxWrite, const char* format, glfVaList args);
	
	int Strcpy_s(char* dst, size_t N, const char* src);
	int Strcmp(const char* str1, const char* str2);
	int Strncmp(const char* str1, const char* str2, size_t num);
	int Stricmp(const char* str1, const char* str2);
	int Strnicmp(const char* str1, const char* str2, size_t num);
	errno_t Strncpy_s(char* dst, size_t maxDst, const char* src, size_t count);
	size_t Strlen(const char* str);

	const char* Strstr(const char* s1, const char* s2);

	size_t Strnlen_s(const char* str, size_t N);
	errno_t Strcat_s(char* dst, size_t N, const char* src);

	const char * Strstr(const char * str1, const char * str2);
	const char * Stristr(const char * str1, const char * str2);
	char * Strstr(char * str1, char * str2);
	const char* Strrchr(const char * str, int ch);
	const char* Strchr(const char * str, int ch);
	char* Strrchr(char * str, int ch);
	char* Strcpy(char* dst, const char* src);

	int ToUpper(int c);
	int ToLower(int c);
	char ToLower(char c);

	void ToLowerCase(char* str, int startoffset = 0, int endoffset = -1);
	void ToLowerCase(std::string& str, int startoffset = 0, int endoffset = -1);

	template<size_t N> 
	int Snprintf_s(char (&str)[N], size_t maxCount, const char* format, ...) {
		glfVaList args;
		glfVaStart(args, format);
		
		int value = Vsnprintf_s(str, N, maxCount, format, args);

		glfVaEnd(args);

		return value;
	}

	template<size_t N> 
	int Sprintf_s(char (&str)[N], const char* format, ...) {
		glfVaList args;
		glfVaStart(args, format);
		
		int value = Vsprintf_s(str, N, format, args);

		glfVaEnd(args);

		return value;
	}
	template<size_t N>
	int Snprintf(char (&str)[N], const char* format, ...) {
		glfVaList args;
		glfVaStart(args, format);
		
		int value = Vsnprintf(str, N, format, args);

		glfVaEnd(args);

		return value;
	}
	
	template<size_t N>
	int Strcpy_s(char (&dst)[N], const char* src) {
		return Strcpy_s(dst, N, src);
	}

	template<size_t N> 
	int Vsnprintf_s(char (&str)[N], size_t maxWrite, const char* format, glfVaList args) {
		return Vsnprintf_s(str, N, maxWrite, format, args);
	}

	template<size_t N>
	int Vsnprintf(char (&str)[N], const char* format, glfVaList args) {
		return Vsnprintf_s(str, N - 1, format, args);
	}

	template<size_t N>
	size_t Strnlen_s(const char (&str)[N]) {
		return Strlen_s(str, N);
	}

	template<size_t N> 
	errno_t Strcat_s(char (&dst)[N], const char* src) {
		return Strcat_s(dst, N, src);
	}

	template<size_t N>
	errno_t Strncpy(char (&dst)[N], const char* src, size_t count) {
		return Strncpy_s(dst, N, src, count);
	}

	//case sensitive string compare, for stl container
	struct LtStr {
		bool operator()(const char* s1, const char* s2) const {
			return Strcmp(s1, s2) < 0;
		}
	};

	//case insensitive string compare, for stl container
	struct LtStri {
		bool operator()(const char* s1, const char* s2) const {
			return Stricmp(s1, s2) < 0;
		}
	};
}

#endif
